﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
using System.Threading;
using System.Timers;

namespace OPCService.Utils
{
    internal class SerialPortClient : IDisposable
    {
        // 串口实例
        private SerialPort _serialPort;
        // 数据缓冲区
        private StringBuilder _dataBuffer;
        // 自动重连计时器
        private System.Timers.Timer _reconnectTimer;
        // 线程锁
        private readonly object _lock = new object();

        // 事件：数据接收
        public event EventHandler<string> DataReceived;
        // 事件：连接状态变化
        public event EventHandler<bool> ConnectionStatusChanged;
        // 事件：错误发生
        public event EventHandler<Exception> ErrorOccurred;

        // 配置参数
        public string PortName { get; set; }
        public int BaudRate { get; set; } = 9600;
        public Parity Parity { get; set; } = Parity.None;
        public StopBits StopBits { get; set; } = StopBits.One;
        public int DataBits { get; set; } = 8;
        public Handshake Handshake { get; set; } = Handshake.None;
        public Encoding Encoding { get; set; } = Encoding.ASCII;
        public string DataEndDelimiter { get; set; } = "\r\n"; // 默认以换行符为数据结束标志
        public int AutoReconnectInterval { get; set; } = 5000; // 自动重连间隔（毫秒）

        // 当前连接状态
        public bool IsOpen => _serialPort?.IsOpen ?? false;

        // 构造函数
        public SerialPortClient(string portName)
        {
            PortName = portName;
            _dataBuffer = new StringBuilder();
            _reconnectTimer = new System.Timers.Timer(AutoReconnectInterval);
            _reconnectTimer.AutoReset = false;
            _reconnectTimer.Elapsed += OnReconnectTimerElapsed;

            InitializeSerialPort();
        }

        // 初始化串口
        private void InitializeSerialPort()
        {
            _serialPort = new SerialPort
            {
                PortName = PortName,
                BaudRate = BaudRate,
                Parity = Parity,
                StopBits = StopBits,
                DataBits = DataBits,
                Handshake = Handshake,
                ReadTimeout = 500,
                WriteTimeout = 500,
                Encoding = Encoding
            };

            _serialPort.DataReceived += OnDataReceived;
            _serialPort.ErrorReceived += OnErrorReceived;
        }

        // 打开串口
        public void Open()
        {
            try
            {
                if (!_serialPort.IsOpen)
                {
                    _serialPort.Open();
                    ConnectionStatusChanged?.Invoke(this, true);
                }
            }
            catch (Exception ex)
            {
                HandleError(ex);
            }
        }

        // 关闭串口
        public void Close()
        {
            try
            {
                if (_serialPort.IsOpen)
                {
                    _serialPort.Close();
                    _reconnectTimer.Stop();
                    ConnectionStatusChanged?.Invoke(this, false);
                }
            }
            catch (Exception ex)
            {
                HandleError(ex);
            }
        }

        // 发送数据（字符串）
        public void Write(string data)
        {
            try
            {
                if (_serialPort.IsOpen)
                {
                    _serialPort.Write(data);
                }
                else
                {
                    HandleError(new InvalidOperationException("串口未打开。"));
                }
            }
            catch (Exception ex)
            {
                HandleError(ex);
            }
        }

        // 发送数据（字节数组）
        public void Write(byte[] data, int offset, int count)
        {
            try
            {
                if (_serialPort.IsOpen)
                {
                    _serialPort.Write(data, offset, count);
                }
                else
                {
                    HandleError(new InvalidOperationException("串口未打开。"));
                }
            }
            catch (Exception ex)
            {
                HandleError(ex);
            }
        }

        // 数据接收事件处理
        private void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                int len = _serialPort.BytesToRead;
                byte[] buffer = new byte[len];
                _serialPort.Read(buffer, 0, len);

                string data = Encoding.GetString(buffer);
                lock (_lock)
                {
                    _dataBuffer.Append(data);

                    // 检查是否包含结束符
                    int delimiterIndex;
                    while ((delimiterIndex = _dataBuffer.ToString().IndexOf(DataEndDelimiter)) != -1)
                    {
                        string frame = _dataBuffer.ToString(0, delimiterIndex);
                        _dataBuffer.Remove(0, delimiterIndex + DataEndDelimiter.Length);

                        // 触发数据接收事件
                        DataReceived?.Invoke(this, frame);
                    }
                }
            }
            catch (Exception ex)
            {
                HandleError(ex);
            }
        }

        // 错误事件处理
        private void OnErrorReceived(object sender, SerialErrorReceivedEventArgs e)
        {
            HandleError(new InvalidOperationException($"串口错误: {e.EventType}"));
        }

        // 自动重连计时器
        private void OnReconnectTimerElapsed(object sender, ElapsedEventArgs e)
        {
            try
            {
                if (!_serialPort.IsOpen)
                {
                    Open();
                }
            }
            catch (Exception ex)
            {
                HandleError(ex);
            }
        }

        // 错误处理
        private void HandleError(Exception ex)
        {
            ErrorOccurred?.Invoke(this, ex);
            _reconnectTimer.Start();
        }

        // CRC16 校验方法（多项式 0x1021）
        private ushort CalculateCRC16(byte[] data)
        {
            ushort crc = 0xFFFF;
            foreach (byte b in data)
            {
                crc ^= (ushort)(b << 8);
                for (int i = 0; i < 8; i++)
                {
                    if ((crc & 0x8000) != 0)
                        crc = (ushort)((crc << 1) ^ 0x1021);
                    else
                        crc <<= 1;
                }
            }
            return crc;
        }

        // CRC 校验验证
        public bool ValidateCRC(byte[] data, int dataLength, ushort expectedCRC)
        {
            byte[] dataToCheck = new byte[dataLength];
            Array.Copy(data, dataToCheck, dataLength);
            ushort calculatedCRC = CalculateCRC16(dataToCheck);
            return calculatedCRC == expectedCRC;
        }

        // 释放资源
        public void Dispose()
        {
            Close();
            _reconnectTimer.Dispose();
            _serialPort.Dispose();
        }
    }
}
